package rexsee.fingerdrawing;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;

public class FingerDrawingView extends View {

	public static String DEFAULT_COLOR = "#222222";
	public static String DEFAULT_BG = "#FEFEFE";
	public static int DEFAULT_WIDTH = 10;

	private final Paint paint = new Paint();
	private final ArrayList<DrawingUnit> units = new ArrayList<DrawingUnit>();
	private final ArrayList<DrawingUnit> cancelUnits = new ArrayList<DrawingUnit>();
	private DrawingUnit currentUnit = null;
	private Bitmap bgBitmap = null;

	public static class DrawingUnit {
		public final Paint paint;
		public final ArrayList<PointF> points = new ArrayList<PointF>();
		public DrawingUnit(Paint p) {
			paint = new Paint();
			paint.setColor(p.getColor());
			paint.setStrokeWidth(p.getStrokeWidth());
			paint.setStyle(Style.FILL);
			paint.setStrokeJoin(Join.ROUND);
			paint.setStrokeCap(Cap.ROUND);
		}
		public void addPoint(PointF point) {
			points.add(point);
		}
		public void draw(Canvas canvas) {
			if (points.size() == 0) return;
			for (int i = 0; i < points.size() - 1; i++) {
				PointF curr = points.get(i);
				PointF next = points.get(i + 1);
				canvas.drawLine(curr.x, curr.y, next.x, next.y, paint);
			}
		}
	}

	public FingerDrawingView(Context context) {
		super(context);
		this.setBackgroundColor(Color.parseColor(DEFAULT_BG));
		this.setClickable(true);
		paint.setColor(Color.parseColor(DEFAULT_COLOR));
		paint.setStrokeWidth(DEFAULT_WIDTH);
		paint.setStyle(Style.FILL);
		paint.setStrokeJoin(Join.ROUND);
		paint.setStrokeCap(Cap.ROUND);
	}

	public void setLineColor(int color) {
		paint.setColor(color);
	}
	public void setBg(int color) {
		bgBitmap = null;
		this.setBackgroundColor(color);
	}
	private void setBg(Bitmap bitmap) {
		bgBitmap = bitmap;
		postInvalidate();
	}
	public void setBg(String path) {
		if (path == null) {
			bgBitmap = null;
			return;
		} else {
			path = path.substring(7);
			int bounds = 480;
			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inJustDecodeBounds = true;
			Bitmap bitmap = BitmapFactory.decodeFile(path, options);
			options.inJustDecodeBounds = false;
			options.inSampleSize = Math.max(1, Math.round(Math.max(options.outHeight / bounds, options.outWidth / bounds)));
			bitmap = BitmapFactory.decodeFile(path, options);
			if (bitmap != null) setBg(bitmap);
		}
	}
	public void setLineWidth(int width) {
		paint.setStrokeWidth(width);
	}

	public int getLineColor() {
		return paint.getColor();
	}
	public float getLineWidth() {
		return paint.getStrokeWidth();
	}

	public void clear() {
		if (units.size() == 0) return;
		for (int i = units.size() - 1; i >= 0; i--) {
			cancelUnits.add(units.get(i));
		}
		units.clear();
		postInvalidate();
	}
	public void goBack() {
		if (units.size() == 0) return;
		DrawingUnit unit = units.get(units.size() - 1);
		units.remove(units.size() - 1);
		cancelUnits.add(unit);
		this.postInvalidate();
	}
	public void goForward() {
		if (cancelUnits.size() == 0) return;
		DrawingUnit unit = cancelUnits.get(cancelUnits.size() - 1);
		cancelUnits.remove(cancelUnits.size() - 1);
		units.add(unit);
		this.postInvalidate();
	}
	public void recover() {
		if (cancelUnits.size() == 0) return;
		for (int i = cancelUnits.size() - 1; i >= 0; i--) {
			units.add(cancelUnits.get(i));
		}
		cancelUnits.clear();
		this.postInvalidate();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		if (action == MotionEvent.ACTION_DOWN) {
			currentUnit = new DrawingUnit(paint);
			units.add(currentUnit);
			cancelUnits.clear();
			PointF point = new PointF();
			point.x = event.getX();
			point.y = event.getY();
			currentUnit.addPoint(point);
			postInvalidate();
		} else if (action == MotionEvent.ACTION_MOVE) {
			PointF point = new PointF();
			point.x = event.getX();
			point.y = event.getY();
			currentUnit.addPoint(point);
			postInvalidate();
		} else if (action == MotionEvent.ACTION_UP) {
		}
		return super.onTouchEvent(event);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (bgBitmap != null) {
			float scale = Math.min((float) getWidth() / (float) bgBitmap.getWidth(), (float) getHeight() / (float) bgBitmap.getHeight());
			int w = (int) (bgBitmap.getWidth() * scale);
			int h = (int) (bgBitmap.getHeight() * scale);
			int t = (getHeight() - h) / 2;
			int l = (getWidth() - w) / 2;
			Rect src = new Rect(0, 0, bgBitmap.getWidth(), bgBitmap.getHeight());
			Rect dst = new Rect(l, t, l + w, t + h);
			canvas.drawBitmap(bgBitmap, src, dst, null);
		}
		if (units.size() == 0) return;
		for (int i = 0; i < units.size(); i++) {
			units.get(i).draw(canvas);
		}
	}

	public Bitmap getBitmap() {
		destroyDrawingCache();
		buildDrawingCache();
		return getDrawingCache();
	}

}
